package thread.threadlocal;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * note:
 * 1. threadLocal 的 set方法就是往 currentThread 的 threadLocalMap 中put一条key=ThreadLocal,val = set的val的数据
 *      1.1 threadLocalMap 底层的实现就是 Entry类, Entry类key=ThreadLocal extends WeakReference<ThreadLocal<?>>  所以可能出现内存泄漏
 * 2. threadLocal 的 get 方法也是从 Thread对象里面的 ThreadLocalMap 中获取值
 * 3. ThreadLocalMap 的 threshold 是 len 的 2/3
 *
 *
 *  内存泄漏产生的原因:  前提 没有手动调用 threadLocal.set(null) / threadLocal.remove()
 *  使用线程池的时候, 线程池里面的线程一直不销毁, 导致这个线程里面的threadLocalMap 里面放了太多的ThreadLocal释放不掉,
 *  而 threadLocal又是弱引用, threadLocalMap 的key会被回收,但是val不会,所以就出现了内存泄漏
 *
 *  Hash冲突怎么解决: 例如 threadLocalMap 里面的entry[].length = 16, 假如第一条数据hash后 index = 1,
 *  第二条数据hash后 index还是等于1, 这时候出现hash冲突, threadLocalMap 发现 index = 1的位置有数据了, 所以会往
 *  后找 index = index + 1 的位置看是否有数据, 没有就放进去, 有就继续往后找, 直到找到为止 (entry[] 有个阀值, 超过阀值会扩容, 所以不会死循环)
 *
 *
 *
 * @author jiangwz
 * @create 2021/3/3.
 */
public class ThreadLocalDemo {
    private static ThreadLocal<Integer> localvariable = ThreadLocal.withInitial(() -> 1);

    private static Integer val = 1;
    private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
    private static ThreadLocal<Integer> local=new ThreadLocal();

    public static void main(String[] args) throws InterruptedException {

//        normalTest();
//        normalTest2();
//        threadLocalTest();

        ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
        System.out.println(threadLocal.get());
        ThreadLocal<Integer> threadLocal2 = ThreadLocal.withInitial(()->2);
        System.out.println(threadLocal2.get());

    }

    private static void normalTest2() {
        local.set(val);
        for(int i=0;i<10;i++){
            Integer localCount = local.get();
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    System.out.println(localCount);
                }
            };
            fixedThreadPool.execute(runnable);
        }
    }

    private static void normalTest() {
        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                ++val;
                System.out.println("线程1： " + val);
            }
        });
        Thread threadTwo = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程2： " + val);
            }
        });
        threadOne.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadTwo.start();
        System.out.println("主线程： " + val);
    }

    private static void threadLocalTest() {
        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                Integer integer = localvariable.get();
                localvariable.set(++integer);
                System.out.println("线程1： " + localvariable.get());
            }
        });
        Thread threadTwo = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程2： " + localvariable.get());
            }
        });
        System.out.println("主线程： " + localvariable.get());
        threadOne.start();
        threadTwo.start();
    }
}
